/*
 * FixedSizeBlockFile.cpp
 *
 *  Created on: Oct 10, 2012
 *      Author: m
 */

#include "FixedSizeBlockFile.h"

namespace physical
{

const openmode FixedSizeBlockFile::defaulOpenmode = std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary;

FixedSizeBlockFile::FixedSizeBlockFile( size_t blockSize, const char filename[], openmode mode ) :
m_blockSource(),
m_blockSize(blockSize)
{
    m_blockSource.exceptions( std::fstream::failbit | std::fstream::badbit );

    if ( filename != NULL && filename[0] != '\0' )
	    this->open( filename, mode );
}

FixedSizeBlockFile::~FixedSizeBlockFile()
{
	this->close();
}

void FixedSizeBlockFile::resetBlockSize( size_t blockSize )
{
    m_blockSize = blockSize;
}

// Lectura Secuencial
void FixedSizeBlockFile::readBlock( byteStream buffer )
{
    m_blockSource.read( buffer, m_blockSize );
}

// Lectura No secuencial
void FixedSizeBlockFile::readBlock( blockNumber position, byteStream buffer )
{
    if ( m_blockSize <= 0 )
        throw InvalidBlockSizeException();

    blockNumber nextPosition = position * m_blockSize;
	m_blockSource.seekp( nextPosition );

	this->readBlock( buffer );
}

void FixedSizeBlockFile::open( const char filename[], openmode mode )
{
    if ( m_blockSource.is_open() )
        return;

    m_blockSource.open( filename, mode | std::ios_base::binary );
}

// TODO: Revisar, la hice medio dormido!!
size_t FixedSizeBlockFile::getFileSize()
{
    std::streampos fsize = 0;
	std::streampos currentPosition = m_blockSource.tellg();

    // compute file size
    m_blockSource.clear();
    m_blockSource.seekg( 0, std::ios::beg );
    fsize = m_blockSource.tellg();
    m_blockSource.clear();
    m_blockSource.seekg( 0, std::ios::end );
    fsize = m_blockSource.tellg() - fsize;
    m_blockSource.clear();
  	m_blockSource.seekg( currentPosition );

    return fsize;
}

size_t FixedSizeBlockFile::getBlocksCount()
{
    if ( m_blockSize <= 0 )
        throw InvalidBlockSizeException();

    return this->getFileSize()/m_blockSize;
}

// Escritura Secuencial
void FixedSizeBlockFile::writeBlock( const byteStream buffer )
{
	m_blockSource.write( buffer, m_blockSize );
}

// Escritura NO Secuencial
void FixedSizeBlockFile::writeBlock( blockNumber position, const byteStream buffer )
{
    if ( m_blockSize <= 0 )
        throw InvalidBlockSizeException();

    blockNumber nextPosition = position * m_blockSize;
	m_blockSource.seekp( nextPosition );

	this->writeBlock(buffer);
}

size_t FixedSizeBlockFile::getBlockSize()
{
	return m_blockSize;
}


size_t FixedSizeBlockFile::gcount()
{
	return m_blockSource.gcount();
}

bool FixedSizeBlockFile::eof()
{
	return m_blockSource.eof();
}

void FixedSizeBlockFile::close()
{
	if ( m_blockSource.is_open() )
	    m_blockSource.close();
}

}
